package com.toocms.jinjuhang.widget.icon_progress

import android.content.Context
import android.content.res.Resources
import android.graphics.*
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.SparseArray
import android.util.TypedValue
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import com.blankj.utilcode.util.LogUtils
import com.toocms.jinjuhang.R
import java.util.regex.Pattern
import kotlin.math.abs
import kotlin.text.Typography.less

class IconProgressView(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, val c: Char) :
    View(context, attrs, defStyleAttr) {
    val oldDrawable = SparseArray<Drawable>() //减少重复获取相同资源
    val paint = Paint()

    @DrawableRes
    var iconId: Int = 0  //左侧图标
        set(value) {
            field = value
            if (0 != iconId) {
                icon = null
            }
            if (isAttachedToWindow) invalidate()
        }

    var icon: Drawable? = null  //左侧图标
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }
        get() {
            if (null == field && 0 != iconId) field = getDrawable(iconId)
            return field
        }

    @ColorInt
    var bgColor = 0xFFCCCCCC.toInt()
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    @ColorInt
    var progressColor = 0xFF0099FF.toInt()
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    @ColorInt
    var startProgressColor: Int = -1
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    @ColorInt
    var centerProgressColor: Int = -1
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    @ColorInt
    var endProgressColor: Int = -1
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    var max: Int = 100 //最大值
        set(value) {
            field = abs(value)
            if (progress > field) {
                progress = field
            }
            if (isAttachedToWindow) invalidate()
        }
    var progress: Int = 0 //进度
        set(value) {
            field = if (abs(value) > max) max else abs(value)
            if (isAttachedToWindow) invalidate()
        }
    var progressTextFormat: String = "%p/%m" //%p 为progress,%m 为max
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    var progressHeightRatio: Float = 1f //进度条高度和图标的高度比，值为0~1
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }
        get() {
            return when {
                field < 0f -> 0f
                field > 1f -> 1f
                else -> field
            }
        }

    var drawablePadding: Int = 0 //图标和进度条的间距（px）

    @ColorInt
    var progressTextColor: Int = 0xFFFFFFFF.toInt()
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    var progressTextSize: Int = 10 //px
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    var progressTextOffset: Int = 0  //偏移进度条右侧的距离(单位：px)
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    var isShowProgressText = true //是否显示当前进度
        set(value) {
            field = value
            if (isAttachedToWindow) invalidate()
        }

    var progressGravity = ProgressGravity.CENTER


    private val progressText: String
        get() {
            var result = StringBuilder(progressTextFormat)
            val pattern = Pattern.compile("%(p|m)")
            val matcher = pattern.matcher(result)
            while (matcher.find()) {
                when (matcher.group()) {
                    "%p" -> result.replace(matcher.start(), matcher.end(), progress.toString())
                    "%m" -> result.replace(matcher.start(), matcher.end(), max.toString())
                }
            }
            return result.toString()
        }


    constructor(context: Context?) : this(context, null)

    constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0, less)

    init {
        attrs?.run {
            context?.obtainStyledAttributes(
                this, R.styleable.IconProgressView, defStyleAttr, 0
            )
        }?.apply {
            icon = getDrawable(R.styleable.IconProgressView_ipIcon)
            bgColor = getColor(R.styleable.IconProgressView_ipBgColor, bgColor)
            progressColor = getColor(R.styleable.IconProgressView_ipProgressColor, progressColor)
            startProgressColor =
                getColor(R.styleable.IconProgressView_ipStartProgressColor, startProgressColor)
            centerProgressColor =
                getColor(R.styleable.IconProgressView_ipCenterProgressColor, centerProgressColor)
            endProgressColor =
                getColor(R.styleable.IconProgressView_ipEndProgressColor, endProgressColor)
            progressGravity = ProgressGravity.codeToGravity(
                getInt(
                    R.styleable.IconProgressView_ipProgressGravity, progressGravity.code
                )
            )
            progressTextOffset = getDimensionPixelSize(
                R.styleable.IconProgressView_ipProgressTextOffset, progressTextOffset
            )
            progressHeightRatio =
                getFloat(R.styleable.IconProgressView_ipProgressHeightRatio, progressHeightRatio)
            max = getInt(R.styleable.IconProgressView_ipMax, max)
            progress = getInt(R.styleable.IconProgressView_ipProgress, progress)
            progressTextFormat =
                getString(R.styleable.IconProgressView_ipProgressTextFormat) ?: "%p/%m"
            progressTextSize = getDimensionPixelSize(
                R.styleable.IconProgressView_ipProgressTextSize, progressTextSize
            )
            drawablePadding = getDimensionPixelSize(
                R.styleable.IconProgressView_ipDrawablePadding, drawablePadding
            )
            progressTextColor =
                getColor(R.styleable.IconProgressView_ipProgressTextColor, progressTextColor)
            isShowProgressText = getBoolean(
                R.styleable.IconProgressView_ipShowProgressText, isShowProgressText
            )
        }
    }


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        var newestWidthMeasureSpec: Int = when (MeasureSpec.getMode(widthMeasureSpec)) {
            MeasureSpec.EXACTLY -> widthMeasureSpec
            MeasureSpec.UNSPECIFIED, MeasureSpec.AT_MOST -> {
                var width = MeasureSpec.getSize(widthMeasureSpec)
                var minWith = 0
                minWith = icon?.intrinsicWidth ?: 0
                paint.reset()
                paint.textSize = progressTextSize.toFloat()
                minWith += paint.measureText(progressText).toInt()
                width = if (width in 1 until minWith) width else minWith
                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY)
            }
            else -> {
                widthMeasureSpec
            }
        }
        var newestHeightMeasureSpec: Int = when (MeasureSpec.getMode(heightMeasureSpec)) {
            MeasureSpec.EXACTLY -> heightMeasureSpec
            MeasureSpec.UNSPECIFIED, MeasureSpec.AT_MOST -> {
                var height = MeasureSpec.getSize(heightMeasureSpec)
                LogUtils.e("height:$height")
                var minHeight = 0
                minHeight = icon?.intrinsicHeight ?: 0
                paint.reset()
                paint.textSize = progressTextSize.toFloat()
                val rect = Rect()
                paint.getTextBounds(progressText, 0, progressText.length, rect)
                minHeight = if (minHeight > rect.height()) minHeight else rect.height()
                height = if (height in 1 until minHeight) height else minHeight
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
            }
            else -> {
                widthMeasureSpec
            }
        }

        super.onMeasure(newestWidthMeasureSpec, newestHeightMeasureSpec)
    }


    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val canvas = canvas ?: return
        val progressRect = progressRect()
        //绘制图标
        drawIcon(canvas)
        //绘制背景
        drawBackground(canvas, progressRect)
        //绘制进度
        drawProgress(canvas, progressRect)
        //绘制文字
        if (isShowProgressText) {
            drawProgressText(canvas, progressRect)
        }
    }

    /**
     * 设置字体大小
     *
     * @param size dp
     */
    fun setProgressTextSize(size: Float) {
        progressTextSize = dp2px(size).toInt()
    }

    /**
     * 设置字体偏移
     *
     * @param size
     */
    fun setProgressTextOffset(size: Float) {
        progressTextOffset = dp2px(size).toInt()
    }

    /**
     * 绘制图标
     *
     * @param canvas
     */
    private fun drawIcon(canvas: Canvas) {
        val drawable = icon
        if (null != drawable && null != canvas) {
            val iconTop = (measuredHeight - drawable.intrinsicHeight) / 2
            val iconLeft = 0 + (if (paddingStart > 0) paddingStart else paddingLeft)
            drawable.setBounds(
                iconLeft,
                iconTop,
                iconLeft + drawable.intrinsicWidth,
                iconTop + drawable.intrinsicHeight
            )
            drawable.draw(canvas)
        }
    }

    /**
     * 绘制背景
     *
     * @param canvas
     */
    private fun drawBackground(canvas: Canvas, progressRect: RectF) {
        if (0f >= progressRect.width() || 0f >= progressRect.height()) return
        paint.reset()
        paint.color = bgColor
        paint.style = Paint.Style.FILL
        drawProgressPath(canvas, progressRect, paint)
    }

    /**
     * 绘制进度
     *
     * @param canvas
     */
    private fun drawProgress(canvas: Canvas, progressRect: RectF) {
        if (0f == progressRect.width()) return
        val progressWidth = progressRect.width() * (progress.toFloat() / max.toFloat())
        val left = progressRect.left
        val top = progressRect.top
        val right = progressRect.left + progressWidth
        val bottom = progressRect.bottom
        paint.reset()
        if (-1 != startProgressColor && -1 != endProgressColor) {
            val colors: IntArray = if (-1 != centerProgressColor) IntArray(3) {
                return@IntArray when (it) {
                    0 -> startProgressColor
                    1 -> centerProgressColor
                    2 -> endProgressColor
                    else -> 0
                }
            } else IntArray(2) {
                return@IntArray when (it) {
                    0 -> startProgressColor
                    1 -> endProgressColor
                    else -> 0
                }
            }
            val positions: FloatArray = if (-1 != centerProgressColor) FloatArray(3) {
                return@FloatArray when (it) {
                    0 -> 0f
                    1 -> 0.5f
                    2 -> 1f
                    else -> 0f
                }
            } else FloatArray(2) {
                return@FloatArray when (it) {
                    0 -> 0f
                    1 -> 1f
                    else -> 0f
                }
            }
            paint.shader = LinearGradient(
                0f, 0f, measuredWidth.toFloat(), 0f, colors, positions, Shader.TileMode.CLAMP
            )
        } else {
            paint.color = progressColor
        }
        paint.style = Paint.Style.FILL
        drawProgressPath(canvas, RectF(left, top, right, bottom), paint)
    }

    /**
     * path
     *
     * @param canvas
     * @param rect
     * @param paint
     */
    private fun drawProgressPath(canvas: Canvas, rect: RectF, paint: Paint) {
        if (0f >= rect.width() || 0f >= rect.height()) return
        val bgPath = Path()
        bgPath.moveTo(rect.left, rect.top)
        bgPath.arcTo(
            rect.left - rect.height() / 2f,
            rect.top,
            rect.left + rect.height() / 2f,
            rect.bottom,
            -90f,
            180f,
            false
        )
        bgPath.lineTo(rect.right + rect.height() / 2f, rect.bottom)
        bgPath.arcTo(
            rect.right - rect.height() / 2f,
            rect.top,
            rect.right + rect.height() / 2f,
            rect.bottom,
            450f,
            -180f,
            false
        )
        bgPath.lineTo(rect.left, rect.top)
        bgPath.close()
        canvas.drawPath(bgPath, paint)
    }


    private fun drawProgressText(canvas: Canvas, progressRect: RectF) {
        if (0f >= progressRect.width() || 0f >= progressRect.height()) return
        paint.reset()
        paint.color = progressTextColor
        paint.style = Paint.Style.FILL
        var textSize = progressTextSize.toFloat()
        if (textSize > progressRect.height()) {
            textSize = progressRect.height()
        }
        paint.textSize = textSize
        val textWidth = paint.measureText(progressText)
        val fontMetrics = paint.fontMetrics
        val baseline = abs(fontMetrics.leading) + abs(fontMetrics.ascent)
        val textHeight = baseline + abs(fontMetrics.descent)
        val x = progressRect.right + progressRect.height() / 2f - textWidth - progressTextOffset
        val y = progressRect.top + (progressRect.height() - textHeight) / 2 + baseline
        canvas.drawText(progressText, x, y, paint)
    }

    /**
     * 获取进度条所在的矩阵
     *
     * @return
     */
    private fun progressRect(): RectF {
        val drawable = icon
        val iconWidth = drawable?.intrinsicWidth?.toFloat() ?: 0f
        val height = progressHeight()
        val paddingHorizontal = when {
            paddingStart != 0 || paddingEnd != 0 -> paddingStart + paddingEnd
            paddingLeft != 0 || paddingRight != 0 -> paddingLeft + paddingRight
            else -> 0
        }
        val paddingLeft = when {
            paddingStart != 0 -> paddingStart
            paddingLeft != 0 -> paddingLeft
            else -> 0
        }
        val paddingRight = when {
            paddingEnd != 0 -> paddingEnd
            paddingRight != 0 -> paddingRight
            else -> 0
        }
        var progressWidth = measuredWidth - paddingHorizontal - iconWidth - height / 2f
        if (0 > progressWidth) progressWidth = 0f
        val left = iconWidth + paddingLeft
        val top = when (progressGravity) {
            ProgressGravity.TOP -> 0f
            ProgressGravity.CENTER -> (measuredHeight - height) / 2f
            ProgressGravity.BOTTOM -> measuredHeight - height
        }
        val right = left + progressWidth + drawablePadding
        val bottom = top + height
        return RectF(left, top, right, bottom)
    }

    /**
     * 获取Drawable
     */
    private fun getDrawable(resId: Int): Drawable? {
        if (0 <= oldDrawable.indexOfKey(resId)) return oldDrawable.get(resId).mutate()
        val drawable = context.getDrawable(resId) ?: return null
        oldDrawable[resId] = drawable
        return drawable.mutate()
    }

    /**
     * dp转px
     */
    private fun dp2px(value: Float) = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP, value, Resources.getSystem().displayMetrics
    )


    /**
     * 进度条高度
     * 注：该方法要在测量后使用
     */
    private fun progressHeight(): Float {
        val drawable = icon
        val iconHeight = drawable?.intrinsicHeight ?: return measuredHeight.toFloat()
        if (iconHeight > measuredHeight) {
            return measuredHeight.toFloat()
        }
        return iconHeight * progressHeightRatio
    }

}